/*******************************************************************************
 * Copyright (c) 2012 laurent barbisan.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    laurent barbisan - initial API and implementation
 *******************************************************************************/

package fr.free.hd.servers.android.geonaute.connector.devices;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;

import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import fr.free.hd.servers.android.geonaute.connector.model.DeviceInfo;
import fr.free.hd.servers.android.geonaute.connector.model.OneDay;
import fr.free.hd.servers.android.geonaute.connector.model.Track;
import fr.free.hd.servers.android.geonaute.connector.model.TrackLap;
import fr.free.hd.servers.android.geonaute.connector.model.TrackPoint;

public class DeviceGH615 {

	public static UsbDevice sDevice = null;
	public static UsbManager sManager = null;

	public static UsbEndpoint getInEndPoint(UsbInterface usbIf)
	{
		for(int i = 0; i < usbIf.getEndpointCount(); i++){
			if(usbIf.getEndpoint(i).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK){
				/*l("Bulk Endpoint");*/
				if(usbIf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN)
					return usbIf.getEndpoint(i);
			}
		}
		
		return null;
	}
	
	public static UsbEndpoint getOutEndPoint(UsbInterface usbIf)
	{
		for(int i = 0; i < usbIf.getEndpointCount(); i++){
			if(usbIf.getEndpoint(i).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK){
				/*l("Bulk Endpoint");*/
				if(usbIf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_OUT)
					return usbIf.getEndpoint(i);
			}
		}
		
		return null;
	}
	
	public static UsbInterface initialize(UsbDeviceConnection conn, UsbDevice dev, UsbManager usbm) {
			
		if (dev == null)
				return null; 
			
			/*l("Interface Count: "+dev.getInterfaceCount());
			l("Using "+String.format("%04X:%04X", sDevice.getVendorId(), sDevice.getProductId()));*/

			if(!conn.claimInterface(dev.getInterface(0), true)) 
				return null;

		   // Take from : http://lxr.free-electrons.com/source/drivers/usb/serial/pl2303.c
		   int VENDOR_WRITE_REQUEST_TYPE       =0x40;
		   int VENDOR_WRITE_REQUEST            =0x01;
		   int VENDOR_READ_REQUEST_TYPE        =0xc0;
		   int VENDOR_READ_REQUEST             =0x01;


			// pl2303_startup(struct usb_serial *serial)			   
			byte[] buff = new byte[10];
			conn.controlTransfer(VENDOR_READ_REQUEST_TYPE,VENDOR_READ_REQUEST ,0x8484, 0, buff, 1, 200);
			conn.controlTransfer(VENDOR_WRITE_REQUEST_TYPE,VENDOR_WRITE_REQUEST ,0x0404, 0, null, 0, 200);
			conn.controlTransfer(VENDOR_READ_REQUEST_TYPE,VENDOR_READ_REQUEST ,0x8484, 0, buff, 1, 200);
			conn.controlTransfer(VENDOR_READ_REQUEST_TYPE,VENDOR_READ_REQUEST ,0x8383, 0, buff, 1, 200);
			conn.controlTransfer(VENDOR_READ_REQUEST_TYPE,VENDOR_READ_REQUEST ,0x8484, 0, buff, 1, 200);
			conn.controlTransfer(VENDOR_WRITE_REQUEST_TYPE,VENDOR_WRITE_REQUEST ,0x0404, 1, null, 0, 200);
			conn.controlTransfer(VENDOR_READ_REQUEST_TYPE,VENDOR_READ_REQUEST ,0x8484, 0, buff, 1, 200);
			conn.controlTransfer(VENDOR_READ_REQUEST_TYPE,VENDOR_READ_REQUEST ,0x8383, 0, buff, 1, 200);
			conn.controlTransfer(VENDOR_WRITE_REQUEST_TYPE,VENDOR_WRITE_REQUEST ,0, 1, null, 0, 200);
			conn.controlTransfer(VENDOR_WRITE_REQUEST_TYPE,VENDOR_WRITE_REQUEST ,1, 0, null, 0, 200);
			//HX special device
			conn.controlTransfer(VENDOR_WRITE_REQUEST_TYPE,VENDOR_WRITE_REQUEST ,2, 0x44, null, 0, 200);

			//pl2303_open
		    conn.controlTransfer(VENDOR_WRITE_REQUEST_TYPE,VENDOR_WRITE_REQUEST ,8, 0, null, 0, 200);
		    conn.controlTransfer(VENDOR_WRITE_REQUEST_TYPE,VENDOR_WRITE_REQUEST ,9, 0, null, 0, 200);
			
			//pl2303_set_termios
			int GET_LINE_REQUEST_TYPE           =0xa1;
			int GET_LINE_REQUEST                =0x21;
			buff = new byte[7];
			conn.controlTransfer(GET_LINE_REQUEST_TYPE,GET_LINE_REQUEST ,0, 0, buff, 7, 200);

			//0...3 : Baud rate
			int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200 };
			int baud = baud_sup[15];
			buff[0] = (byte)(baud & 0xff);
			buff[1] = (byte)((baud >> 8) & 0xff);
			buff[2] = (byte)((baud >> 16) & 0xff);
			buff[3] = (byte)((baud >> 24) & 0xff);
			
			/* For reference buf[4]=0 is 1 stop bits */
			/* For reference buf[4]=1 is 1.5 stop bits */
			/* For reference buf[4]=2 is 2 stop bits */
			buff[4] = 0;
			
		    /* For reference buf[5]=0 is none parity */
			/* For reference buf[5]=1 is odd parity */
			/* For reference buf[5]=2 is even parity */
			/* For reference buf[5]=3 is mark parity */
			/* For reference buf[5]=4 is space parity */
			buff[5] =0;
			//6: Bit size, 5,6,7,8
			buff[6]=8;
			
			int SET_LINE_REQUEST_TYPE           =0x21;
			int SET_LINE_REQUEST                =0x20;
			conn.controlTransfer(SET_LINE_REQUEST_TYPE,SET_LINE_REQUEST ,0, 0, buff, 7, 200);
			
			byte[] buffResult = new byte[7];
			conn.controlTransfer(GET_LINE_REQUEST_TYPE,GET_LINE_REQUEST ,0, 0, buffResult, 7, 200);
			
			//Break
			/*int BREAK_REQUEST_TYPE              =0x21;
			int BREAK_REQUEST                   =0x23;
			int BREAK_ON                        =0xffff;
			int BREAK_OFF                       =0x0000;
			
			  conn.controlTransfer(BREAK_REQUEST_TYPE,BREAK_REQUEST ,BREAK_ON, 0 , null, 0, 200);
			  
			//Control Line
			int SET_CONTROL_REQUEST_TYPE        =0x21;
			int SET_CONTROL_REQUEST             =0x22;
			int CONTROL_DTR                     =0x01;
			int CONTROL_RTS                     =0x02;
			
			conn.controlTransfer(SET_CONTROL_REQUEST_TYPE,SET_CONTROL_REQUEST ,CONTROL_DTR, 0, null, 0, 200);*/
			
			return dev.getInterface(0);		
		}
	
   
    public static void ExportTrackToKML(Track trk, String filename) {
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(
                    new OutputStreamWriter(
                    new FileOutputStream(filename), "UTF-8"));
        } catch (IOException ex) {
            System.out.println(ex.toString());
        }

        try {
            bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            bw.newLine();
            bw.write("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
            bw.newLine();
            bw.write("  <Document>");
            bw.newLine();
            bw.write("    <name>GPS Data " + trk.toString() + "</name>");
            bw.newLine();
            bw.write("    <description>"
                    + "Duration - " + trk.getTrackDurationString() + "\n"
                    + "Distance - " + (double) trk.Distance / 1000 + "\n"
                    + "Speed - " + trk.AvgSpeed + " (top speed - " + trk.TopSpeed + ")" + "\n"
                    + "</description>");
            bw.newLine();
            bw.write("    <Placemark>");
            bw.newLine();
            bw.write("      <Style>id=\"linestyle\"");
            bw.newLine();
            bw.write("        <LineStyle>");
            bw.newLine();
            bw.write("          <color>7f0000ff</color>");
            bw.newLine();
            bw.write("          <width>4</width>");
            bw.newLine();
            bw.write("        </LineStyle>");
            bw.newLine();
            bw.write("      </Style>");
            bw.newLine();
            bw.write("      <name>Path</name>");
            bw.newLine();
            bw.write("      <styleUrl>#lineStyle</styleUrl>");
            bw.newLine();
            bw.write("      <LineString>");
            bw.newLine();
            bw.write("        <extrude>1</extrude>");
            bw.newLine();
            bw.write("        <tessellate>1</tessellate>");
            bw.newLine();
            bw.write("        <coordinates>");
            bw.newLine();

            for (TrackPoint tp : trk.tps) {
                Double lon = (double) tp.Lon / 1000000;
                Double lat = (double) tp.Lat / 1000000;
                String pointstring = "          "
                        + lon.toString() + ", "
                        + lat.toString() + ", "
                        + tp.Alt.toString();
                bw.write(pointstring);
                bw.newLine();
            }

            bw.write("        </coordinates>");
            bw.newLine();
            bw.write("      </LineString>");
            bw.newLine();
            bw.write("    </Placemark>");
            bw.newLine();
            bw.write("  </Document>");
            bw.newLine();
            bw.write("</kml>");

            bw.close();
        } catch (IOException ex) {
            System.out.println(ex.toString());
        }
    }

    public static void ExportTrackToGPX(Track trk, String filename) {
    }

    public static int uByteToInt(byte b) {
        return (int) b & 0xFF;
    }
}
